package cn.xyt.dto;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.tom.db.jdbc.simple.DBUtil;
import cn.tom.kit.io.PropertiesUtil;
import cn.tom.kit.io.Resource;
import cn.xyt.server.ServerBootStart;
import cn.xyt.service.MessageService;

/**
 * 电池计算 规则
 * @author tomsun
 */
public class Battery {
	public final static Logger logger = LoggerFactory.getLogger(Battery.class);
	public double U = 60; //额定电压 TODO 自动矫正, 设置后不修改
	public double total_ah = 20;  // 总电池容量 默认 20AH  //TODO 自动矫正, 设置后不修改
	public double tc_u;  //停车电压
	public double av_u;  //平均停车电压
	public double C_U = U*1.1;  //充电平均电压电压 默认稳定充电60V
	public double C_I = total_ah * 0.125; //充电平均电流电流
	public double P; // P= UI
	public double W_1D; // 1度 W= p * 1小时 --> 总电量/1小时
	public double hour; // 充电时间
	public int btype;
	
	/**
	 * 剩余电量百分比,当前电量百分比,  
	 * 数据库查询, 
	 * 运行中, curr_percent = 数据库查询数据, 随时更新
	 * 在充电过程中随时更新, curr_percent = added_percent
	 * 根据上报电池数据实时更新  实时更新
	 */
	public double curr_percent;
	public double last_percent;  //上次充电前电量百分比 记录
	public double rchange_percent;// 充电前电量百分比
	public double add_percent; // 当次充上电百分比 = add_ah/current_ah
	public double add_ah ; //当次充电电量 = 稳定充电电流 * 充电时间(充满状态为止)*转换损耗
	public double current_ah ; // 当前容量 = add_ah/(1-last_percent)
	
	public double life =1;  // 电池寿命
	public double cd_sh =0.99; //第一次充电损耗 电量转换率99%
	public int t; //温度
	public double cd_hour; //预计充电时间
	
	/**
	 * Y代表剩余电量百分比，计算得大于1即100%，小于0即0%；x代表停车电压；X代表有效计算电压；T代表温度（app进入车辆页面时即时更新的温度，无数据则默认app登陆温度）
	 * 其他额定电压：
		额定电压n，寿命80%以上； y = -0.00034216X³*(60/n)³ + 0.066737X²*(60/n)²- 4.2181X*(60/n)+ 86.942
		额定电压n，寿命60%~80%;  y = -0.00083979X³*(60/n)³+ 0.16047X²*(60/n)²- 10.092X *(60/n)+ 209.392
		额定电压n，寿命60%以下;  y = -0.00072372X³*(60/n)³ + 0.13931X²*(60/n)² - 8.8037X *(60/n)+ 183.125
		X=x+(25-T)n/1200
	 */
	public void getLastPercent(){  // 需要参数 tc_u  t U life
		if(tc_u<U*0.8){
			last_percent = 0;
		}else{
			if(btype==0){
				qm_last_mileage(); //铅酸
			}else{
				li_last_mileage(); //锂电池
			}
		}
		if(energy_100==0) energy_100 = 1.6;
		last_mileage = current_ah*last_percent/(energy_100/C_U)/10;
		
		if(C_I==0)  C_I= 20 * 0.125;
		/*剩余充电时间*/
		if(curr_percent>0.95){
			// 剩余充电时间
			cd_hour = (1-last_percent)*current_ah*3/C_I;
		}else{
			cd_hour = (0.95-last_percent)*current_ah/C_I
					+0.05*current_ah*3/C_I;
		}
	}
	
	
	public void init(){  //需要参数 life C_I hour total_ah current_ah last_percent
		if(C_U==0) C_U = U*1.1;
		//充电损耗
		if(life>0.9){cd_sh = 0.95;}else if(life>0.8 ){cd_sh = 0.93;}else if(life>0.7){	cd_sh = 0.92;}
		else if(life>0.6){cd_sh = 0.91;}else if(life>0.5){cd_sh = 0.90;}else{cd_sh = 0.89;}
		if(current_ah>total_ah || current_ah<total_ah*0.6){ //小于8安时 按照新的来
			 //默认计算按照手机定位温度
			 //<5度 total_ah*0.7	,5~15 total_ah*0.8, 15~25, total_ah*0.9, 25以上,total_ah*1
			current_ah = total_ah;
			if(t<=25) current_ah = total_ah*0.9;
			if(t<=15) current_ah = total_ah*0.8;
			if(t<5) current_ah = total_ah*0.7;
			//按默认算法
		}
	}
	
	public void charge(){
		/*当次充电电量 = 稳定充电电流 * 充电时间(充满状态为止)*转换损耗*/
		add_ah = C_I * hour *cd_sh; //开始充电时间, 记录 每次更新当前值
		if(add_ah==0) C_I=20 * 0.125;
		if(rchange_percent==0) rchange_percent=0.3;
		
		//现在容量÷额定容量, add_ah=0 的时候计算一下
		life = current_ah/total_ah;
		
		//增加的充电百分比 
		add_percent = add_ah/current_ah;
		//充电时的当前电量百分比
		curr_percent = add_percent + rchange_percent;
		if(curr_percent==0) curr_percent = 0.5;
		if(curr_percent>=1) curr_percent = 1;
		if(curr_percent>0.95){
			// 剩余充电时间
			cd_hour = (1-curr_percent)*current_ah*3/C_I;
		}else{
			cd_hour = (0.95-curr_percent)*current_ah/C_I
					+0.05*current_ah*3/C_I;
		}
		
		last_mileage = current_ah*curr_percent/(energy_100/C_U)/10;
		
		if(add_ah>0){
			// current_ah当前容量 = add_ah/(1-last_percent)
			current_ah =add_ah/(1-rchange_percent);  //充满电更新
			
			//现在容量÷额定容量
			life = current_ah/total_ah;
		}
		
	}
	
	
	/******里程****/
	public double max_speed; //最大时速
	public double max_pl; //历史最大频率
	public double cur_mcs; //当日脉冲数, 根据位来取累加
	/* 脉冲计算规则最大时速max_speed(app设置)/历史最大频率(sql时间段)(上报获取)/3600*1.1*/
	public double mcxs = 0.00005;  // 脉冲里程系数 默认 0.00005
	public double current_mileage;  //当前里程 = 脉冲系数 * 当日脉冲数(上报)
	public double enery_milleage;  //当前里程 = 脉冲系数 * 当日脉冲数(上报)
	/*充满电后返回到25% 的行驶里程*/
	public double current25_mileage;
	//当次充电量*充电平均电压÷充完电后使用后至原电量值所行驶里程*100÷1000
	public double energy_100 =1.6; //百公里能耗
	public double last_mileage; // 剩余预估里程
	
	
	public void getMileage() {
		if(max_pl ==0) max_pl =200;
		// 自动调整的脉冲里程系数 当日最大时速（手机gps/车辆gps）÷当日最大频率÷3600*110%
		mcxs = max_speed/max_pl/3600*1.1; // 已设置为主, 设置过了, 不修改
		//日行驶里程 
		current_mileage = mcxs * cur_mcs; 
//		if(today_mileage>20){
//			//充电后使用后至原电量值锁行驶里程：该次实际行驶里程÷（1+充电前电量百分比—行驶后电量百分比）（原电量剩余50%以下有效）
//			current25_mileage  = (today_mileage+current_mileage)/(1+rchange_percent-last_percent);
//			//百公里能耗:上次充电量*充电平均电压÷充完电后使用后至原电量值所行驶里程*100÷1000
//			energy_100 = add_ah*C_U/current25_mileage*100/1000;
//		}
		getEnergy();
	}
	
	public void getEnergy(){
		 //当次的耗电量÷当次的行驶里程÷10
		 //当次的耗电量：(1-m%)*现在的容量*平均使用电压；
		av_u = av_u==0?tc_u:(av_u+tc_u)/2;
		double i = (1-last_percent)*current_ah*av_u;
		energy_100 = i/(enery_milleage+current_mileage)/10;
		if(energy_100 == 0)  energy_100=1.6;
	}
	
	/**
	 * 
		标准电压     100%    50%          0%
		  72V           84         73            68
		  60V           71.4      62            56
		  48V           53      50.5            46
		  36V          41.5V    38V     34.5V

		  锂电池 剩余电量
	 */
	public double li_last_mileage(){
		Map<Double, Double[]> map = new HashMap<>();
		map.put(72D, new Double[]{82D, 73d, 68d});
		map.put(60D, new Double[]{70d, 62d, 56d});
		map.put(48D, new Double[]{53.5d, 48d, 43d});
		map.put(36D, new Double[]{41.5, 38d, 34.5});
		Double[]  f =  map.get(U);
		double  f_max = f[0];
		double  f_middle = f[1];
		double  f_min = f[2];
		if(tc_u >= f_max) last_percent = 1;
		if(tc_u <= f_min) last_percent=  0;
		if(tc_u>= f_middle && tc_u<f_max){
			last_percent =  (tc_u-f_middle)/(f_max - f_middle)*0.5 + 0.5;
		}
		
		if(tc_u< f_middle && tc_u>f_min){
			last_percent = ((tc_u-f_min)/(f_middle-f_min))*0.5;
		}
		return last_percent;
	}
	
	private double qm_last_mileage(){
		double x = tc_u+(30-t)*U/900;  //TODO 调整后 数据 不对 68V停车电压, 电量超过100%
		if(life>=0.8){
			last_percent = -0.00034216*Math.pow(x, 3)* Math.pow(60/U,3) +0.066737*Math.pow(x, 2)*Math.pow(60/U,2)-4.2181*x*(60/U)+86.942;
		}else if(life>=0.6){
			last_percent = -0.00083979*Math.pow(x, 3)* Math.pow(60/U,3) +0.16047*Math.pow(x, 2)*Math.pow(60/U,2)-10.092*x*(60/U)+209.392;
		}else{
			last_percent = -0.00072372*Math.pow(x, 3)* Math.pow(60/U,3) +0.13931*Math.pow(x, 2)*Math.pow(60/U,2)-8.8037*x*(60/U)+183.125;
		}
		//预估里程= 现在容量*剩余电量百分比÷（该次百公里能耗÷充电平均电压+上一次百公里能耗÷充电平均电压+上上次百公里能耗÷充电平均电压）*3÷10；
		//如果没有百公里能耗数值默认值为1.88度;括号里面有几组数据就是乘以几的奇数；
		if(last_percent>1) last_percent=1;
		if(last_percent<0) last_percent=0;
		return last_percent; 
	}
	
	@Override
	public String toString() {
		return "Battery [U=" + U + ", tc_u=" + tc_u + ", C_U=" + C_U + ", C_I=" + C_I + ", P=" + P + ", W_1D=" + W_1D + ", hour=" + hour + ", total_ah=" + total_ah + ", curr_percent=" + curr_percent + ", last_percent=" + last_percent + ", rchange_percent=" + rchange_percent + ", add_percent=" + add_percent + ", add_ah=" + add_ah + ", current_ah=" + current_ah + ", life=" + life + ", cd_sh=" + cd_sh + ", t=" + t + ", cd_hour=" + cd_hour + ", max_speed=" + max_speed + ", max_pl=" + max_pl + ", cur_mcs=" + cur_mcs + ", mcxs=" + mcxs + ", current_mileage=" + current_mileage + ", enery_mileage=" + enery_milleage + ", current25_mileage=" + current25_mileage + ", energy_100=" + energy_100 + ", last_mileage=" + last_mileage + "]";
	}

	public static Battery parseBattery(VoltInfo voltInfo, Map<String, Object> map){
		Battery battery = new Battery(); //life C_I hour total_ah current_ah last_percent
		battery.life = (float) map.get("life");
		battery.U = map.get("volt") ==null ? 48 :(int) map.get("volt") ;
		battery.total_ah =  map.get("ah")  ==null ? 20 :(int) map.get("ah") ;
		int cnt = (int)map.get("cnt");
		battery.C_I = cnt==0?0: ((BigDecimal) map.get("t_i")).doubleValue()/cnt;
		battery.C_U = cnt==0?0: ((BigDecimal) map.get("t_u")).doubleValue()/cnt;
		battery.rchange_percent = (float) map.get("rchange_percent");
		battery.current_ah = (float) map.get("curr_an");
		battery.hour = (double) map.get("hour");
		battery.energy_100 = (float) map.get("energy_100");
		battery.tc_u = voltInfo.volt;
		battery.av_u = (double)map.get("av_u");
		battery.t = (int) map.get("t");
		battery.max_pl = (int) map.get("max_pl");
		battery.max_speed = map.get("max_speed")==null? 40: (int)map.get("max_speed");
		battery.enery_milleage = (int)map.get("enery_milleage");
		battery.cur_mcs = voltInfo.mlcnt;
		battery.btype = (int)map.get("btype");
		battery.init();
		logger.info(battery.toString());//TODO 用来测试数据
		return battery;
	}
	
	/*
	 * 标准电压     100%    50%          0%
		  72V           84         73            63
		  60V           71.4      62            52
		  48V           54.6      48            42
		  锂电池 剩余电量
	 */
	public static void main(String[] args) throws Exception {
		Resource resource = new Resource("DBConfig.properties");
		Properties props = PropertiesUtil.loadProperties(resource);
		DBUtil.init(props);
		short a = 0;
		VoltInfo voltInfo = new VoltInfo(2424, 79.2F, "00000010", 0F, "10000000", a, 0, Calendar.getInstance());

		String _sql = "select life,energy_type,btype, t_u,t_i,cnt, curr_an,enery_milleage, rchange_percent,last_percent,av_u,curr_percent, "
				+ "c.ah,c.volt,a.state,max_pl,max_speed,energy_100, begint::date,charge_state,t,curr_milleage,"
				+ "(date_part('hour', endt- begint) + date_part('minute', endt- begint)/60) as hour, a.ctime from "
				+ "battery a left join deviceset c on c.deviceid = a.did where a.did = ?";
		Map<String, Object> map = DBUtil.getMap(_sql, voltInfo.deviceid);
		//Battery [U=72.0, tc_u=87.0, C_U=80.9, C_I=0.0, P=0.0, W_1D=0.0, hour=0.0, total_ah=20.0, curr_percent=0.0, last_percent=0.0, rchange_percent=0.6932231187820435, add_percent=0.0, add_ah=0.0, current_ah=18.0, life=1.0, cd_sh=0.95, t=25, cd_hour=0.0, max_speed=40.0, max_pl=294.0, cur_mcs=0.0, mcxs=5.0E-5, current_mileage=0.0, enery_mileage=8.0, current25_mileage=0.0, energy_100=0.0, last_mileage=0.0]
		//Battery [U=72.0, tc_u=86.4, C_U=80.9, C_I=0.0, P=0.0, W_1D=0.0, hour=0.0, total_ah=20.0, curr_percent=0.0, last_percent=0.0, rchange_percent=0.6932231187820435, add_percent=0.0, add_ah=0.0, current_ah=18.0, life=1.0, cd_sh=0.95, t=25, cd_hour=0.0, max_speed=40.0, max_pl=294.0, cur_mcs=0.0, mcxs=5.0E-5, current_mileage=0.0, enery_mileage=8.0, current25_mileage=0.0, energy_100=0.0, last_mileage=0.0]
		new MessageService().workout(voltInfo);
		
		// 48.7 --29
		//46.2 7
	}

	
}
